//------------------------------------------------------------------------------
//!	@file	BldInfo.c
//!	@brief
//!		Generate Build Information files
//!
//!	@Description
//!		This program outputs three files:
//!		- A C file that contains a compilable version of the build information
//!		- A text file that contains a build log
//!		- A text file that contains the last build information
//!
//!	Creation Date:	12/14/2002 2:48:42 PM
//!
//!	$Id: bldinfo.c 201 2013-12-27 18:32:38Z ac.verbeck@gmail.com $
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//	Copyright and Disclaimer Notice
//
//	Copyright (c) 2012 A.C. Verbeck
//
//	This file is part of SM: A State Machine Library.
//
//	SM is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	SM is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with SM.  If not, see <http://www.gnu.org/licenses/>.
//
//------------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <time.h>
#include <popt.h>

//------------------------------------------------------------------------------
// Local defines
//------------------------------------------------------------------------------
#define OPT_OUTPUT	0x01
#define OPT_PROJECT	0x02
#define OPT_VERSION	0x04
#define OPT_CPP		0x08

#define MAX_FN	128

//------------------------------------------------------------------------------
// Local data
//------------------------------------------------------------------------------
typedef struct BUILD_INFOtag {
	char*	pFile;
	char*	pProject;
	char*	pVersion;
	int		nBuildID;
	char*	userName;
	char*	computerName;
	char*	t_str;
} BUILD_INFO;

static poptContext optCon;
static char*	popt_Output;
static char*	popt_Project;
static char*	popt_Version;
static int		popt_CPP = 0;

static char		time_buff[50]	= {0};

//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------
static void h_file_write(BUILD_INFO* pbi);
static void c_file_write(BUILD_INFO* pbi);
static void cpp_file_write(BUILD_INFO* pbi);
static void id_file_read(BUILD_INFO* pbi);
static void id_file_write(BUILD_INFO* pbi);
static void log_file_write(BUILD_INFO* pbi);
static void time_acq(void);

//------------------------------------------------------------------------------
// Main function
//------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
	BUILD_INFO	bld;

	int	nIdx;
	unsigned short int	options=0;
	unsigned short int	t_opt=0;

	struct poptOption optionsTable[] = {
		{ "output",  'o', POPT_ARG_STRING, &popt_Output,  'o', "output file root (no extension)", NULL },
		{ "project", 'p', POPT_ARG_STRING, &popt_Project, 'p', "project id",                      NULL },
		{ "version", 'v', POPT_ARG_STRING, &popt_Version, 'v', "version",                         NULL },
		{ "cpp",     'c', POPT_ARG_NONE,   &popt_CPP,     'c', "Language: C++",                   NULL },
		POPT_AUTOHELP
		POPT_TABLEEND
	};

//------------------------------------------------------------------------------
//	Argument processing
//------------------------------------------------------------------------------
	optCon = poptGetContext(NULL, argc, (const char **)argv, optionsTable, 0);
	poptSetOtherOptionHelp(optCon, "[options]");

	if (argc < 2) {
		poptPrintUsage(optCon, stderr, 0);
		exit(1);
	}

	while ((nIdx = poptGetNextOpt(optCon)) >= 0) {
		switch (nIdx) {
		case 'o':
			options |= OPT_OUTPUT;
			break;
		case 'p':
			options |= OPT_PROJECT;
			break;
		case 'v':
			options |= OPT_VERSION;
			break;
		case 'c':
			options |= OPT_CPP;
			break;
		}
	}
	if (nIdx<-1) {
		fprintf(stderr, "%s: %s\n",
		        poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
		        poptStrerror(nIdx));
		exit(1);
	}

	t_opt = options & (OPT_OUTPUT|OPT_PROJECT|OPT_VERSION);
	if (t_opt != (OPT_OUTPUT|OPT_PROJECT|OPT_VERSION)) {
		printf("This program requires an output file stem, a project name and a version ID.\n");
		poptPrintUsage(optCon, stderr, 0);
		exit(1);
	}

//------------------------------------------------------------------------------
//	Get the time
//------------------------------------------------------------------------------
	time_acq();																	// Get the time

//------------------------------------------------------------------------------
//	Fill in the build information structure
//------------------------------------------------------------------------------
	bld.pFile		= popt_Output;												// Output file string
	bld.pProject	= popt_Project;												// Project string
	bld.pVersion	= popt_Version;												// Version string
	bld.nBuildID	= 0;														// ID string
	bld.t_str		= time_buff;												// Set the time
	bld.userName	= getenv("USERNAME");
	bld.computerName = getenv("COMPUTERNAME");

//------------------------------------------------------------------------------
//	Create / Update the following files:
//	- update id file
//	- create h file
//	- create c or c++ file
//	- create log file
//------------------------------------------------------------------------------
	id_file_read(&bld);															// Read id file
	h_file_write(&bld);															// Generate h file

	if (popt_CPP == 0)
		c_file_write(&bld);														// Generate c file
	else
		cpp_file_write(&bld);													// Generate c++ file

	id_file_write(&bld);														// Update id file
	log_file_write(&bld);														// Generate log file

	return 0;
}

//------------------------------------------------------------------------------
//!	@brief
//!		write the header file
//!
//!	@param
//!		BUILD_INFO*
//!
//!	@return
//!		none
//------------------------------------------------------------------------------
static void h_file_write(BUILD_INFO* pbi)
{
	char	File_Name[MAX_FN];													// Filename
	FILE*	pF_file = NULL;														// Output file pointer

	strcpy(File_Name, pbi->pFile);												// Get filename
	strcat(File_Name, ".h");													// Add extension
	pF_file = fopen(File_Name,"w");												// Open output file

	if (pF_file == NULL) {
		printf("Could not open %s\n", File_Name);
		exit(1);
	}

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tFile Name:\n");
	fprintf(pF_file,"//\t\t%s\n",File_Name);

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tDescription:\n");
	fprintf(pF_file,"//\t\t%s build information header.\n", pbi->pProject);
	fprintf(pF_file,"//\t\tNote:  This is a generated file.  Do not edit.\n");

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tDate:\n");
	fprintf(pF_file,"//\t\t%s\n", pbi->t_str);
	fprintf(pF_file,"//\n");

	fprintf(pF_file,"\n");
	fprintf(pF_file,"void bldinfoPrintBldInfo(void);\n");
	fprintf(pF_file,"\n");

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tEnd of: %s\n", File_Name);
	fprintf(pF_file,"//\n");

	fclose(pF_file);
}

//------------------------------------------------------------------------------
//!	@brief
//!		write the c (code) file
//!
//!	@param
//!		BUILD_INFO*
//!
//!	@return
//!		none
//------------------------------------------------------------------------------
static void c_file_write(BUILD_INFO* pbi)
{
	char	File_Name[MAX_FN];													// Filename
	FILE*	pF_file = NULL;														// Output file pointer

	strcpy(File_Name, pbi->pFile);												// Get filename
	strcat(File_Name, ".c");													// Add extension
	pF_file = fopen(File_Name,"w");												// Open output file

	if (pF_file == NULL) {
		printf("Could not open %s\n", File_Name);
		exit(1);
	}

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tFile Name:\n");
	fprintf(pF_file,"//\t\t%s\n", File_Name);

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tDescription:\n");
	fprintf(pF_file,"//\t\t%s build information.\n", pbi->pProject);
	fprintf(pF_file,"//\t\tNote:  This is a generated file.  Do not edit.\n");

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tDate:\n");
	fprintf(pF_file,"//\t\t%s\n",pbi->t_str);
	fprintf(pF_file,"//\n");

	fprintf(pF_file,"#include <stdio.h>\n");

	fprintf(pF_file,"\n");
	fprintf(pF_file,"static char* ID_project = \"%s\";\n", pbi->pProject);
	fprintf(pF_file,"static char* ID_version = \"%s\";\n", pbi->pVersion);
	fprintf(pF_file,"static char* ID_build = \"%d\";\n", pbi->nBuildID);
	fprintf(pF_file,"static char* ID_date = \"%s\";\n", pbi->t_str);
	fprintf(pF_file,"static char* ID_user = \"%s\";\n", pbi->userName);
	fprintf(pF_file,"static char* ID_computer = \"%s\";\n", pbi->computerName);
	fprintf(pF_file,"\n");

	fprintf(pF_file,"\n");
	fprintf(pF_file,"void bldinfoPrintBldInfo(void)\n");
	fprintf(pF_file,"{\n");

	fprintf(pF_file,"    printf(\"Project: %%s\\n\", ID_project);\n");
	fprintf(pF_file,"    printf(\"Version: %%s\\n\", ID_version);\n");
	fprintf(pF_file,"    printf(\"Build ID: %%s\\n\", ID_build);\n");
	fprintf(pF_file,"    printf(\"Build Date: %%s\\n\", ID_date);\n");
	fprintf(pF_file,"    printf(\"User Name: %%s\\n\", ID_user);\n");
	fprintf(pF_file,"    printf(\"Computer Name: %%s\\n\", ID_computer);\n");

	fprintf(pF_file,"}\n");
	fprintf(pF_file,"\n");

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tEnd of: %s\n", File_Name);
	fprintf(pF_file,"//\n");

	fclose(pF_file);
}

//------------------------------------------------------------------------------
//!	@brief
//!		write the c++ (code) file
//!
//!	@param
//!		BUILD_INFO*
//!
//!	@return
//!		none
//------------------------------------------------------------------------------
static void cpp_file_write(BUILD_INFO* pbi)
{
	char	File_Name[MAX_FN];													// Filename
	FILE*	pF_file = NULL;														// Output file pointer

	strcpy(File_Name, pbi->pFile);												// Get filename
	strcat(File_Name, ".cpp");													// Add extension
	pF_file = fopen(File_Name,"w");												// Open output file

	if (pF_file == NULL) {
		printf("Could not open %s\n", File_Name);
		exit(1);
	}

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tFile Name:\n");
	fprintf(pF_file,"//\t\t%s\n", File_Name);

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tDescription:\n");
	fprintf(pF_file,"//\t\t%s build information.\n", pbi->pProject);
	fprintf(pF_file,"//\t\tNote:  This is a generated file.  Do not edit.\n");

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tDate:\n");
	fprintf(pF_file,"//\t\t%s\n",pbi->t_str);
	fprintf(pF_file,"//\n");

	fprintf(pF_file,"#include <string>\n");
	fprintf(pF_file,"#include <iostream>\n");

	fprintf(pF_file,"\n");
	fprintf(pF_file,"static const std::string ID_project = \"%s\";\n", pbi->pProject);
	fprintf(pF_file,"static const std::string ID_version = \"%s\";\n", pbi->pVersion);
	fprintf(pF_file,"static const std::string ID_build = \"%d\";\n", pbi->nBuildID);
	fprintf(pF_file,"static const std::string ID_date = \"%s\";\n", pbi->t_str);
	fprintf(pF_file,"static const std::string ID_user = \"%s\";\n", pbi->userName);
	fprintf(pF_file,"static const std::string ID_computer = \"%s\";\n", pbi->computerName);
	fprintf(pF_file,"\n");

	fprintf(pF_file,"\n");
	fprintf(pF_file,"void bldinfoPrintBldInfo(void)\n");
	fprintf(pF_file,"{\n");


	fprintf(pF_file,"\tstd::cout << \"Project: \" << ID_project << std::endl;\n");
	fprintf(pF_file,"\tstd::cout << \"Version: \" << ID_version << std::endl;\n");
	fprintf(pF_file,"\tstd::cout << \"Build ID: \" << ID_build << std::endl;\n");
	fprintf(pF_file,"\tstd::cout << \"Build Date: \" << ID_date << std::endl;\n");
	fprintf(pF_file,"\tstd::cout << \"User Name: \" << ID_user << std::endl;\n");
	fprintf(pF_file,"\tstd::cout << \"Computer Name: \" << ID_computer << std::endl;\n");

	fprintf(pF_file,"}\n");
	fprintf(pF_file,"\n");

	fprintf(pF_file,"//\n");
	fprintf(pF_file,"//\tEnd of: %s\n", File_Name);
	fprintf(pF_file,"//\n");

	fclose(pF_file);
}

//------------------------------------------------------------------------------
//!	@brief
//!		read the ID file
//!
//!	@param
//!		BUILD_INFO*
//!
//!	@return
//!		none
//------------------------------------------------------------------------------
static void id_file_read(BUILD_INFO* pbi)
{
	char	File_Name[MAX_FN];													// File name buffer
	FILE*	pF_file;															// Input file pointer

	strcpy(File_Name, pbi->pProject);											// Base for ID filename
	strcat(File_Name, ".id");													// ID extension
	pF_file = fopen(File_Name, "r");											// Input file pointer
	if (pF_file == NULL) {
		printf("Creating %s\n", File_Name);
		pbi->nBuildID = 1;
		id_file_write(pbi);
	} else {
		fscanf(pF_file, "%d", &pbi->nBuildID);
		fclose(pF_file);
		++pbi->nBuildID;
	}
}

//------------------------------------------------------------------------------
//!	@brief
//!		write the ID file
//!
//!	@param
//!		BUILD_INFO*
//!
//!	@return
//!		none
//------------------------------------------------------------------------------
static void id_file_write(BUILD_INFO* pbi)
{
	char	File_Name[MAX_FN];													// File name buffer
	FILE*	pF_file;															// Input file pointer

	strcpy(File_Name, pbi->pProject);											// Base for ID filename
	strcat(File_Name, ".id");													// ID extension
	pF_file = fopen(File_Name, "w");											// Input file pointer
	if (pF_file == NULL) {
		printf("Could not open %s\n", pbi->pFile);
		exit(1);
	}
	fprintf(pF_file, "%d\n", pbi->nBuildID);
	fclose(pF_file);
}

//------------------------------------------------------------------------------
//!	@brief
//!		Write the build file log
//!
//!	@param
//!		BUILD_INFO*
//!
//!	@return
//!		none
//------------------------------------------------------------------------------
static void log_file_write(BUILD_INFO* pbi)
{
	char	File_Name[MAX_FN];													// File name buffer
	FILE*	pF_file;															// Input file pointer

	strcpy(File_Name, pbi->pProject);											// Base for ID filename
	strcat(File_Name, ".log");													// ID extension
	pF_file = fopen(File_Name, "a");											// Input file pointer
	if (pF_file == NULL) {
		printf("Could not open %s\n", pbi->pFile);
		exit(1);
	}

	fprintf(pF_file, "%s, %s, %d, %s, %s\n", pbi->pProject, pbi->t_str, pbi->nBuildID, pbi->userName, pbi->computerName);
	fclose(pF_file);
}

//------------------------------------------------------------------------------
//!	@brief
//!		Acquire the time
//!
//!	@param
//!		none
//!
//!	@return
//!		none
//------------------------------------------------------------------------------
static void time_acq(void)
{
	time_t	t_curr		= time(NULL);											// Get the time
	struct	tm*	t_local	= localtime(&t_curr);									// Make time into tm structure

	strftime(time_buff, 50, "%Y-%m-%d %H:%M:%S", t_local);						//	Create the time string
}


//
//	 End of BldInfo.c
//
